#include <memory.h>
#include <iostream>
#include <thread>
#include <vector>

#include "ql_oe.h"
#include "iconv.h"
#include "ql_mcm_sms.h"

#include "sms.hpp"
#include "misc.h"
#include "defines.hpp"

std::unique_ptr< sms > sms::ptSMS;

void on_recv_msg( QL_SMS_MsgRef ptSMS , void * obj )
{
	if( obj == nullptr ) return;
	if( ptSMS == nullptr ) return;
	sms * p_sms = ( sms *) obj;
	__show_line( "alsdjflasdjflsajdflskajdfasldfkjasldfjlsadjflsad");
	std::string from( ptSMS->src_addr );

	sms::sms_type t;
	switch( ptSMS->format ){
	case E_QL_SMS_FORMAT_GSM_7BIT:
		t = sms::GSM_7BIT;
		break;
	case E_QL_SMS_FORMAT_BINARY_DATA:
		t = sms::BIN;
		break;
	case E_QL_SMS_FORMAT_UCS2:
		t = sms::UCS2;
		break;
	default:
	__show_line( "***********************");
		return;
	}
	// 
	//p_sms->on_recv( from , ptSMS->sms_data_len , ptSMS->sms_data , t );
	size_t len = ptSMS->sms_data_len;
	char * ptdata = ptSMS->sms_data;
	std::thread thd([ from , len , ptdata, t , p_sms ]{
		__show_line( "alsdjflasdjflsajdflskajdfasldfkjasldfjlsadjflsad");
		char * data = ( char *)malloc( len + 1 );
		
		if( data != nullptr ){

			memcpy( data , ptdata , len );
			data[ len ] = 0;
			// 回调到对象内部进行处理数据
			p_sms->on_recv( from , len , data , t );
			
			free( data );
		}
	});
	thd.detach();
}

static int EXSMS_sIsRegisterToNW(void)
{
	E_QL_NW_RADIO_ACCESS_TYPE_T eRat = E_QL_NW_RAT_GSM;
	E_QL_WWAN_NET_REG_STATE_T eState = E_QL_WWAN_REG_NOT_REGISTERED;
	int iRssi = 0;
	int iBer = 0;
	int iResult = 0;

	iResult = QL_NW_GetRegState(&eRat, &eState, &iRssi, &iBer);
	if(iResult != 0){
		return -1;
	}

	if( (eState != E_QL_WWAN_REG_REGISTERED_HOME_NETWORK) && (eState != E_QL_WWAN_REG_ROAMING) ) {
		return -1;
	}

	return 0;
}

sms::sms()
{
	int e = 0;
	m_is_lock = false;
	e = QL_SMS_Client_Init( &m_handle );
	// 注册接收短信的回调函数
	if( e == 0 ){
		ptSMS.reset( this );
	  	QL_SMS_AddRxMsgHandler( on_recv_msg , this );
		nw_client_handle_type         m_net_handle;
		e = QL_MCM_NW_Client_Init( &m_net_handle );
		if( e == 0 ){
			QL_MCM_NW_OPERATOR_NAME_INFO_T info;
			e = QL_MCM_NW_GetOperatorName( m_net_handle ,&info );
			__show_line_2();
			if( e == 0 ){
				m_is_ok = true;
				__show_line_1( "%sGet network operator name: %s%s%s" , TYELLOW , TBLUE , info.mnc , TNORMAL );
				std::string str(info.mnc);
				if( str.find("03" ) !=std::string::npos ||
					str.find("05") != std::string::npos ||
				 	str.find("11") != std::string::npos ){
					m_is_telcom = true;
					__show_line_2();
				}else{
					m_is_telcom = false;
					__show_line_2();
				}
			}
		}
		QL_MCM_NW_Client_Deinit( m_net_handle );
  	}else{
	  	std::cout << "Initialize SMS fail." << std::endl;
		abort();
	}
}


void sms :: __waitUnlock()
{
	while( m_is_lock == true ){
		std::this_thread::yield();
		std::this_thread::sleep_for( std::chrono::milliseconds( 500 ));
	}
}

size_t sms :: __fillGSMData( const std::string& msg , sms_type t , ql_sms_info_t& sms )
{
	char * data = nullptr;
	size_t real_len = 0;

	//if( m_is_telcom == true ){
		real_len = msg.length();
		memcpy( sms.sms_data , msg.c_str() , real_len );
		__show_line_1( "%s real_len = %s%ld%s" , TYELLOW , TBLUE , real_len , TNORMAL );
	/*}else{
		real_len = ASCII2GSM( msg.c_str() , msg.length() , &data );
		if( data != nullptr )
			memcpy( sms.sms_data , data , real_len );
		else real_len = 0;
		__show_line_2();
	}*/
	sms.format  = E_QL_SMS_FORMAT_GSM_7BIT;
	__show_line_1( "%sSend a GSM SMS:%s%s %s" , TYELLOW , TBLUE , msg.c_str() , TNORMAL );

	if( data != nullptr ) free( data );
	sms.sms_data_len 	= real_len;
	if( real_len > 139 ) real_len = 139;									 	// 只发送140个字节
	sms.sms_data[ real_len ] = '\0';

	return real_len;
}

size_t sms :: __fillUCS2Data( const std::string& msg , sms_type t , ql_sms_info_t& sms )
{
	char * data = nullptr;
	size_t real_len = 0;

	real_len = GBK2UCS2( msg.c_str() , msg.length() , &data );
	
	if( data != nullptr ){
		memcpy( sms.sms_data , data , real_len );
		sms.format  		= E_QL_SMS_FORMAT_UCS2;

		free( data );
	}
	__show_line_1( "%sSend a UCS2 SMS:%s %s%s" , TYELLOW , TBLUE  , msg.c_str() , TNORMAL );
	sms.sms_data_len 	= real_len;
	if( real_len > 139 ) real_len = 139;									 	// 只发送140个字节
	sms.sms_data[ real_len ] = '\0';

	return real_len;
}

size_t sms :: __fillData( const std::string& msg , sms_type t , ql_sms_info_t& sms )
{
	// 设置短信参数
	size_t  real_len = 0;
	sms.e_storage  	= E_QL_SMS_STORAGE_TYPE_NONE;
	sms.type 		= E_QL_SMS_TYPE_TX;
	sms.e_mode 		= E_QL_SMS_MESSAGE_MODE_GW;
	switch( t ){
	case GSM_7BIT:
	case TEXT:
		real_len = __fillGSMData( msg , t , sms );
		break;
	case BIN:	
		sms.format  		= E_QL_SMS_FORMAT_BINARY_DATA; 		
		real_len 			= 0;
	break;
	case UCS2:
		real_len = __fillUCS2Data( msg , t , sms );
		break;
	default: m_is_lock = false;return 0;
	}

	// 设置短信内容

	return real_len;
}

size_t sms::send( const std::string& phone , const std::string& msg , sms_type t )
{
	size_t ret = 0;

	if( EXSMS_sIsRegisterToNW() != 0 ){
		__show_line_1( "%sNetwork fail, send sms fail%s" , TRED , TNORMAL );
		return ret;
	}

	__waitUnlock();
	m_is_lock = true;
	
	ql_sms_info_t   sms;
	memset( &sms , 0 , sizeof( sms ));
	// 填充短信数据
	ret = __fillData( msg , t , sms );
	__show_line( sms.sms_data );
	if( ret > 0 ){
		// 设置目标电话号码
		memcpy( sms.src_addr , phone.c_str() , phone.length() );
		sms.src_addr[ phone.length() ] = 0;
		__show_line( sms.src_addr );
		// 发送短信
		int e = QL_SMS_Send_Sms( m_handle , &sms );
		__show_line_1( "%s Send SMS result code = %s%d %s" , TYELLOW , TBLUE , e , TNORMAL );

		if( e ){// 发送失败
			err_code e1 = ERR_SEND_FAIL;
			ret = 0;
		
			if( cb_on_send ){ cb_on_send( e1 ); }
		}
		else{ // 成功发送
			ret = msg.size();
			if( cb_on_send ){ cb_on_send( OK ); }
		}
	}
		
	m_is_lock = false;

	return ret;
}

size_t sms::send( const std::string& phone , size_t len , const char * msg , sms_type t )
{
  	size_t ret = 0;
	std::string str( msg );
	if( str.length() != len ){
		return 0;
	}
	ret = send( phone , str , t );
	return ret;
}

void sms::on_recv( const std::string& from , size_t len , const char * msg , sms_type t )
{
	if( msg == nullptr ) return;
	char * 		data = nullptr;
	size_t 		real_len = len;
	__show_line("***************************************");
	switch( t ){
		case GSM_7BIT:
		case TEXT:
		__show_line("----------------------------------------------");
			data = ( char *)( msg );
			#if defined( __DEBUG__ )
				std::cout << TYELLOW << "Recv a SMS FROM:" << TBLUE << from
					<< TYELLOW << "MSG content:" << TBLUE << data << std::endl;
			#endif
			if( cb_on_msg && data ){
				std::string str( data );
				str += "\r";
				cb_on_msg( from , str.c_str() , str.length() , t );
			}
		break;
		case BIN:
		default:
			data = ( char *)msg;
			if( cb_on_msg && data ){
				cb_on_msg( from , data ,  real_len, t );
			}
		break;
		case UCS2:
			//real_len = UCS2GBK( msg , len , &data );
		break;
	}
}

size_t sms:: GSM2ASCII( const char * from , size_t len ,  char ** data )
{
	__show_line_1( "%s-----------------------------------%s" , TRED  , TNORMAL );
	int shift = len % 7;// 计算移位步长
	
	size_t ret = 0;
	std::vector< uint8_t > rst_v;
	__show_line_1( "%s11111111111111111111111111111111%s" , TRED  , TNORMAL );
	// 抽取高位数字的模板，shift只是从那个位置取模板
	uint8_t tmp[ 8 ] = { 0x0 , 0x80 , 0xc0 , 0xe0 , 0xf0 , 0xf8 , 0xfc , 0xfe };
	for( size_t i = len; i >= 0 ; i-- , shift-- ){// 从最后的字节开始进行向前解码
	__show_line_1( "%s i = %d , len = %d %s" , TRED , i , len  , TNORMAL );
		uint8_t d = from[ i ];
		if( i > 0 ){
			d = d << shift;
			d +=( ( from[ i - 1 ] & tmp[ shift ] ) >> ( 8 - shift ) );
			if( shift == 0 ){ shift = 7; }
		}
		__show_line_1( "%s3333333333333333333333%s" , TRED  , TNORMAL );
		rst_v.insert( rst_v.begin() , d ); // 解码结果
	}
	__show_line_1( "%srst_v.size = %d%s" , TRED , rst_v.size() , TNORMAL );
	ret = rst_v.size();
	if( *data == nullptr ){
		*data = ( char *)malloc( ret );
	}else{
		*data = ( char*)realloc( *data , ret );
	}

	if( *data == nullptr ){ return 0; }

	memcpy( data , rst_v.data() , ret );
	
	return ret;
}

size_t sms:: ASCII2GSM( const char * from , size_t len , char ** data )
{
	int shift = 1;
	size_t ret = len - len / 8;

	if( *data == nullptr ){
		*data = ( char *)malloc( ret );
		if( *data == nullptr ){	return 0; }
	}

	char *rst = * data;
	size_t group_count = len / 8;
	if( len % 8 > 0 ) group_count ++;
	unsigned char __d [ 8 ];
	size_t cp_len = 8;

	for( size_t j = 0; j < group_count; j ++ ){
		if( j < group_count - 1 ) cp_len = 8;
		else if( len % 8 > 0 )cp_len = ( len % 8 );
		else cp_len = 8;

		memcpy( __d , from + j * 8 , cp_len );
		for( size_t i = 0 ; i < cp_len ; i ++ , shift ++ ){
			if( i == 0 ) shift = 1;

			char d = __d[ i ];
			unsigned char temp = 0xff;
			temp >>= shift;
			d = ( d  >> ( shift - 1 ) );
			if( i + 1 < cp_len ){
				temp = 0xff;
				temp <<= ( 8 - shift );
				char d1 = ( __d[ i + 1 ] << ( 8 - shift ));
				d1 &= temp;		d |= d1;		*rst = d;
				if( i != 7 ) rst ++;

			}else{
				*rst = d;
				if( i != 7 ) rst ++;
			}
		}
	}
	return ret;
}

size_t sms:: GBK2UCS2( const char * from , size_t len , char ** data )
{
	size_t ret = len;
	iconv_t ctx = iconv_open("UCS-2" , "GBK" );

	if( ctx >= 0 ){
		if( *data == nullptr ){
			*data = ( char * )malloc( len + 1 );
			memset( *data , 0 , len + 1 );
			if( *data == nullptr ){
				return 0;
			}
		}
		char *f = ( char *)from;
		char * o = *data;
		size_t il = len , ol = len;
		iconv( ctx ,&f , &il , &o , &ol );
		iconv_close( ctx );
	}
	return ret;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
sms * GetSMSHandle()
{
	if( sms::ptSMS ){
		return sms::ptSMS.get();
	}

	return nullptr;
}
